﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;

using System.IO.Ports;

using cc2530.Lib;

using cc2530.Lib.device;


namespace cc2530.Lib.device
{
    /// <summary>
    /// 网卡转串口类
    /// </summary>
    public class RawS2T
    {

#region 本地变量

        TapWin tap;

        SerialPort serialport;


        Thread serialThread;
        Thread tapThread;

        RingSigleBuf ringbufserial = new RingSigleBuf(TapWin.BUF_SIZE);
        AutoResetEvent ARESerial = new AutoResetEvent(false);
       

#endregion

        #region 常量

        static int MAX_RECV_BUF_LEN = (int)(TapWin.BUF_SIZE * 10);
        const int SLIP_END = 0xc0;
        const int SLIP_ESC = 0xdb;
        const int SLIP_ESC_END = 0xdc;
        const int SLIP_ESC_ESC = 0xdd;

        #endregion

        #region construction ,disconstruction ,properties

        public TapWin MyTap { get { return this.tap; } }

        public RawS2T(string comName, string adapterkey) {
            serialport = new SerialPort(comName);
            serialport.BaudRate = 38400;
            serialport.ReadTimeout = 5;
            serialport.WriteTimeout = 5;
            tap = new TapWin(adapterkey);
        }

        public bool IsSerialOpen { get {
            if (serialport == null || serialport.IsOpen == false) return false;
            return true;
        } }

        public bool IsTapOpen { get {
            if (tap == null || tap.IsOpen == false) return false;
            return true;
        } }
        #endregion


        #region 事件

        /// <summary>
        /// 四个事件用来监控数据的收发
        /// </summary>
        public event Ulitily.OnTransferHandler onSerialPortReceiveHandler;
        public event Ulitily.OnTransferHandler onSerialPortSendHandler;
        public event Ulitily.OnTransferHandler onTapReceiveHandler;
        public event Ulitily.OnTransferHandler onTapSendHandler;

        /// <summary>
        /// 返回的数据为实现要发送的数据--两个事件用来变更接口的数据
        /// </summary>
        public event Ulitily.OnTransationHandler onTransationS2T;
        public event Ulitily.OnTransationHandler onTransationT2S;

        #endregion



        #region 公有

        public int SetSerialPort(string com)
        {
            try
            {
                if (serialport != null)
                {
                    serialport.Close();

                }
                serialport = new SerialPort(com);
                serialport.BaudRate = 38400;
                serialport.ReadTimeout = 5;
                serialport.WriteTimeout = 5;
                return 0;
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.ToString());
                return -1;
            }
        }


        /// <summary>
        /// 打开串口
        /// </summary>
        /// <returns></returns>
        public int OpenSerialPort()
        {
            try {
                serialport.Open();
                if (serialport.IsOpen) {

                    serialport.DataReceived += serialport_DataReceived;

                    if (serialThread != null) serialThread.Abort();
                    serialThread = new Thread(SerialThread);
                    serialThread.Name = "SerialThread";
                    serialThread.Start();

                    return 0;
                }
                else return -2;
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.ToString());
                serialThread = null;
                return -1;
            }
        }

        void serialport_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                //throw new NotImplementedException();
                int btr = serialport.ReadBufferSize;
                if (btr > 0)
                {
                    if (btr > TapWin.BUF_SIZE) btr = TapWin.BUF_SIZE;
                    byte[] sb = new byte[TapWin.BUF_SIZE];
                    int sl = serialport.Read(sb, 0, btr);
                    ringbufserial.WriteBuf(sb, sl);
                    ARESerial.Set();
                }
            }
            catch {
                ARESerial.Set();
            }
        }

        /// <summary>
        /// 打开tap
        /// </summary>
        /// <returns></returns>
        public bool OpenTapWin()
        {
            try {
                if (tap.TapWin_Open()) {

                    if (tapThread != null) tapThread.Abort();
                    tapThread = new Thread(TapThread);
                    tapThread.Name = "TapThread";
                    tapThread.Start();
                    return true;
                }
                else return false;
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.ToString());
                return false;
            }
        }


        /// <summary>
        /// 关闭串口
        /// </summary>
        /// <returns></returns>
        public int CloseSerialPort()
        {
            try {
                serialport.Close();
                if (serialport.IsOpen) return -2;
                else {
                    if (serialThread != null)
                    {
                        serialThread.Abort();
                        serialThread = null;
                    }
                }
                return 0;
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.ToString());
                return -1;
            }
        }

        /// <summary>
        /// 关闭tap
        /// </summary>
        /// <returns></returns>
        public int CloseTapWin()
        {
            try {
                tap.TapWin_Close();
                if (tapThread != null)
                {
                    tapThread.Abort();
                    tapThread = null;
                }
                return 0;
            }
            catch (Exception e) {
                System.Console.WriteLine(e.ToString());
                return -1;
            }
        }


        /// <summary>
        /// 写入 com
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public int WriteSerialPort(byte[] buffer, int len)
        {
            byte[] sendbuf = new byte[len * 2];

            int offset = 0;
            sendbuf[offset++] = RawS2T.SLIP_END;
            for (int i = 0; i < len; i++) {
                switch(buffer[i])
                {
                    case RawS2T.SLIP_END:
                        sendbuf[offset++] = RawS2T.SLIP_ESC;
                        sendbuf[offset++] = RawS2T.SLIP_ESC_END;
                        break;
                    case RawS2T.SLIP_ESC:
                        sendbuf[offset++] = RawS2T.SLIP_ESC;
                        sendbuf[offset++] = RawS2T.SLIP_ESC_ESC;
                        break;
                    default:
                        sendbuf[offset++] = buffer[i];
                        break;
                }
            }

            sendbuf[offset++] = RawS2T.SLIP_END;
            serialport.Write(sendbuf, 0, offset);

            return len;
        }

        /// <summary>
        /// 写入tap
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public int WriteTap(byte[] buffer, int len)
        {
            tap.WriteData(buffer, len);
            return len;
        }
        

        #endregion


        #region 线程

        void SerialThread()
        {
            TransationBase tbuffer = new TransationBase();
            tbuffer.data =  new byte[MAX_RECV_BUF_LEN];
            tbuffer.datalen = 0;
            TransationBase result = tbuffer;
            while (true)
            {
                try
                {
                    //从串口读数据----------------slip protocol--------------------//
                    ARESerial.WaitOne(100,false);
                    while (ringbufserial.DataLen > 0)
                    {
                        byte c = ringbufserial.ReadByte();
                        if (tbuffer.datalen >= MAX_RECV_BUF_LEN) tbuffer.datalen = 0;
                        switch (c)
                        { 
                            case SLIP_END:


                                if (tbuffer.datalen > 0) { 
                                    //接收完成
                                    if (onSerialPortReceiveHandler != null)
                                    {
                                        TransationBase args = tbuffer.DeepClone() as TransationBase;
                                        onSerialPortReceiveHandler(this, args);
                                    }

                                    //写入tap
                                    if (tap != null && tap.IsOpen == true)
                                    {
                                        ///事件处理过程中，用户通过 返回args来 转换发送数据
                                        if (onTransationS2T != null)
                                        {
                                            TransationBase args = tbuffer.DeepClone() as TransationBase;
                                            result  = onTransationS2T(this, args);
                                        }


                                        ///用户有数据返回，直接写tap,用户没有数据返回，不写入
                                        if (result != null) tap.WriteData(result.data, result.datalen);

                                        if (onTapSendHandler != null && result != null)
                                        {
                                            onTapSendHandler(this, result);
                                        }
                                    }

                                    //处理完毕
                                    tbuffer.datalen = 0;
                                }
                                break;

                            case SLIP_ESC:
                                if (ringbufserial.IsEmpty())
                                {
                                    tbuffer.data[tbuffer.datalen++] = c;
                                }
                                else{
                                    c = ringbufserial.ReadByte();
                                    switch (c)
                                    { 
                                        case SLIP_ESC_END:
                                            c = SLIP_END;
                                            break;
                                        case SLIP_ESC_ESC:
                                            c = SLIP_ESC;
                                            break;
                                        default: break;
                                    }

                                    tbuffer.data[tbuffer.datalen++] = c;
                                }
                                break;
                            default:
                                tbuffer.data[tbuffer.datalen++] = c;
                                break;
                        }
                    }
                }
                catch (Exception e)
                {
                    System.Console.WriteLine("SerialThread :"+e.ToString());
                }

            }
        }

        void TapThread()
        {
            TransationBase tbuffer = new TransationBase();
            tbuffer.data = new byte[TapWin.BUF_SIZE];
            tbuffer.datalen = 0;
            TransationBase result = tbuffer;

            while (true)
            {
                try
                {
                    if (tap.IsOpen)
                    {
                        //从网络中读取数据
                        tbuffer.datalen = tap.ReadData(tbuffer.data, TapWin.BUF_SIZE);
                        if (tbuffer.datalen > 0)
                        {
                            ///从tap中读数据事件
                            if (onTapReceiveHandler != null)
                            {
                                TransationBase args = tbuffer.DeepClone() as TransationBase;
                                onTapReceiveHandler(this, args);
                            }

                            if (serialport != null && serialport.IsOpen)
                            {
                                if (onTransationS2T != null)
                                {
                                    TransationBase t = tbuffer.DeepClone();
                                    try
                                    {
                                        ///给上层使用，用于协议转换
                                        result = onTransationT2S(this, tbuffer.DeepClone());
                                    }
                                    catch (Exception ee)
                                    {
                                        System.Console.WriteLine("on transation serial to tap error:"+ee.ToString());
                                    }
                                }

                                //必须变成 slip编码
                                if (result != null) this.WriteSerialPort(result.data, result.datalen);


                                //写入serial 事件
                                if (onSerialPortSendHandler != null && result != null)
                                {
                                    onSerialPortSendHandler(this, result);
                                }
                            }
                        }

                    }

                }
                catch (Exception e){

                    System.Console.WriteLine("TapThread :"+e.ToString());
                }
            }

        }
        
        
        #endregion

        #region 私有
       
        #endregion
    }
}
